// 将示例代码封装在一个函数中
pub fn run_examples() {
  println!("===== Rust struct 示例 =====\n");

  // 1. 结构体基础使用
  println!("1. 结构体基础使用:");
  example_1();

  // 2. 单元结构体
  println!("\n2. 单元结构体:");
  example_2();

  // 3. 元组结构体
  println!("\n3. 元组结构体:");
  example_3();

  // 4. 结构体整体标可变, 某个字段不能指定为可变.
  println!("\n4. 结构体整体标可变, 某个字段不能指定为可变:");
  example_4();

  // 5. 打印结构体
  println!("\n5. 打印结构体:");
  example_5();

  // 6. 结构体所有权
  println!("\n6. 结构体所有权:");
  example_6();

  // 7. 结构体解构
  println!("\n7. 结构体解构:");
  example_7();
}

struct Person {
  name: String,
  age: u8,
}
// 1. 结构体基础使用
fn example_1() {
  let p = Person {
    name: String::from("sunface"),
    age: 30,
  };
  println!("    // 对于结构体，我们必须为其中的每一个字段都指定具体的值");
  println!("    struct Person {{ name: String, age: u8 }}");
  println!("    let p = Person {{ name: String::from(\"sunface\"), age: 30 }}");
  println!("    name: {}, age: {}", p.name, p.age);

}

struct Logger;
impl Logger {
  fn log(&self, message: &str) {
    println!("    logger.log(): {}", message);
  }
}
// 2. 单元结构体
fn example_2() {
  let logger = Logger;
  println!("    // 单元结构体没有任何字段. 用于只关心类型的行为, 而不需要状态");
  println!("    struct Logger;");
  println!("    impl Logger {{ ... }}");
  println!("    let logger = Logger;");
  logger.log("this is a log");

}

struct Color(i32, i32, i32);
// 3. 元组结构体
fn example_3() {
  let v = Color(0, 127, 255);
  check_color(v);
  println!("    // 元组结构体看起来跟元组很像, 但是它拥有一个结构体的名称");
  println!("    struct Color(i32, i32, i32);");
  println!("    let v = Color(0, 127, 255);");
}

fn check_color(rgb: Color) {
  let Color(r, g, b) = rgb;
  assert_eq!(r, 0);
  assert_eq!(g, 127);
  assert_eq!(b, 255);
}

// 4. 结构体整体标可变, 某个字段不能指定为可变.
fn example_4() {
  let mut age = 18;
  let p = Person {
    name: String::from("sunface"),
    age: age
  };
  age = 30;
  println!("    // 注意下列初始化, 本该 let mut p, 定为是整体可变的的.");
  println!("    let mut age = 18");
  println!("    let p = Person {{ name: String::from(\"sunface\"), age: age }}");
  println!("    p.age = 30; // 报错 cannot mutate immutable variable `p`");
  println!("    age = 30; // age: {} and p.age: {}", age, p.age);
}


// 5. 打印结构体
#[derive(Debug)]
struct Rectangle {
  width: u32,
  height: u32,
}
fn example_5() {
  let scale = 2;
  let rect1 = Rectangle {
    width: 30 * scale, // 打印 debug 信息到标准错误输出 stderr,并将 `30 * scale` 的值赋给 `width`
    height: 50,
  };
  println!("    // 直接为结构体实现 Debug trait 特征");
  println!("    #[derive(Debug)]");
  println!("    struct Rectangle {{ ... }}");
  println!("    let rect1 = Rectangle {{ width: 30, height: 50 }};");
  println!("    // width: {}, height: {} // 要求 {{}} 能够打印的, 是需要实现 Display 特征的", rect1.width, rect1.height);
  println!("    println!(\"{{:?}}\", rect1); // 而 {{:?}} 打印的, 是需要实现 Debug 特征的");
  println!("    {:?}", rect1); // 打印 debug 信息到标准输出 stdout
}


// 6. 结构体所有权
struct File {
  name: String,
  size: u32,
}
fn example_6() {
  let f = File { name: String::from("readme.md"), size: 56 };

  let _name = f.name;
  let _size = f.size;

  println!("    // 结构体的变量中一部分的所有权会被转移给其它变量");
  println!("    let f = File {{ name: String::from(\"readme.md\"), size: 56 }};");
  println!("    let _name = f.name;");
  println!("    let _size = f.size;");
  println!("    f.name; // 再次访问 f.name 报错: use of moved value: `f.name`");
  println!("    f.size: {}; // f.size 还能访问, 因为它 u32 有 Copy 特征, 复制变量", f.size);
}


// 7. 结构体解构
#[derive(Debug)]
struct User {
  active: bool,
  username: String,
  email: String,
  sign_in_count: u64,
}
fn set_email(u: User) -> User {
  User {
    email: String::from("contact@im.dev"),
    ..u
  }
}
fn example_7() {
  let u1 = User {
    email: String::from("someone@example.com"),
    username: String::from("sunface"),
    active: true,
    sign_in_count: 1,
  };
  let u2 = set_email(u1);
  println!("    // 解构了 u, 属性的所有权也都拿走");
  println!("    fn set_email(u: User) -> User {{ User {{ email: String::from(\"contact@im.dev\"), ..u }} }}");
  println!("    let u2 = set_email(u1);");
  println!("    u2 value: {}, {}, {}, {}", u2.email, u2.username, u2.active, u2.sign_in_count);
  println!("    u2: {:?}", u2);
}